#include "cybertron/node/WorkApp.hpp"
#include "cybertron/core/Log.hpp"
#include "cybertron/network/Message.hpp"
#include "cybertron/core/UtilStateHelper.hpp"
#include "cybertron/core/UtilConsole.hpp"
#include "cybertron/core/UtilCurl.hpp"
#include "cybertron/core/UtilDirectory.hpp"
#include "cybertron/core/Log.hpp"
#include <thread>

CYBERTRON_BEGIN

WorkApp::WorkApp(){
    zeroMembers();
}

WorkApp::~WorkApp(){
}

void WorkApp::zeroMembers(){
    mAgentPublicIP = "127.0.0.1";
	mAgentConnectIp = "127.0.0.1";
    mpAgentClient = nullptr;
    mbAgentThreadRunning = false;
	mbstateCheckThreadRunning = false;
	mbTaskHaveRun = false;
    mWorkId = "";
    mTaskId = "";
    mWorkType = Common::EWorkNodeType_None;
    mWorkState = Common::EWorkNodeStateStarting;
	mServerListenPort = 0;
	mAgentListenPort = 0;
	mLicenseState = false;
}

int WorkApp::parseArguments(int argc, char* argv[])
{
	logInfo("WorkApp ====> parseArguments %d", argc);
    if (argc < 4){
        logWarning("Too less arguments. need four or more arguments: --task_id <task id> --node_id <node id>");
        return -1;
    }

	for (int i = 1; i < argc; ++i)
	{
		std::string arg = argv[i];
		if (arg == "--node_id")
		{
			++i;
			if (i < argc)
			{
				mWorkId = std::string(argv[i]);
			}
		}
		else if (arg == "--task_id")
		{
			++i;
			if (i < argc)
			{
				mTaskId = std::string(argv[i]);
			}
		}
		else if (arg == "--work_type")
		{
			++i;
			if (i < argc)
			{
				mWorkType =(Common::EWorkNodeType)atoi(argv[i]);
				logInfo("worktype ====> %d", mWorkType);
			}
		}
		else if (arg == "--work_name")
		{
			++i;
			if (i < argc)
			{
				mWorkName =argv[i];
				logInfo("mWorkName ====> %s", mWorkName.c_str());
			}
		}
		else if (arg == "--agent_id")
		{
			++i;
			if (i < argc)
			{
				mAgentId = std::string(argv[i]);

			}
		}
		else if (arg == "--public_ip")
		{
			++i;
			if (i < argc)
			{
				mAgentPublicIP = std::string(argv[i]);
				logInfo("PublicIP ====> %s", mAgentPublicIP.c_str());
			}
		}
		else if (arg == "--agent_listen_port")
		{
			++i;
			if (i < argc)
			{
				std::string AgentListenPort = std::string(argv[i]);
				mAgentListenPort = atoi(AgentListenPort.c_str());
				logInfo("agent_listen_port ====> %d", mAgentListenPort);
			}
		}
		else if (arg == "--web_ip")
		{
			++i;
			if (i < argc)
			{
				mWebIP = std::string(argv[i]);
				logInfo("web ip ====> %s", mWebIP.c_str());
			}
		}
		else if (arg == "--web_port")
		{
			++i;
			if (i < argc)
			{
				mWebPort = std::string(argv[i]);
				logInfo("web port ====> %s", mWebPort.c_str());
			}
		}
		else if (arg == "--agent_connect_ip")
		{
			++i;
			if (i < argc)
			{
				mAgentConnectIp = std::string(argv[i]);
				logInfo("agent connect ip ====> %s", mAgentConnectIp.c_str());
			}
		}
		/*std::string mWebIP;
		int mWebPort;*/
        else{
            logWarning("Unknown arguments: %s", argv[i]);
            //return false;
        }
		if ( i >= argc){
			return -1;
		}
	}
	return 0;
}

int WorkApp::parseArguments(string flag, string value)
{
	{
		std::string arg = flag;
		if (arg == "--node_id")
		{
			mWorkId = value;
		}
		else if (arg == "--task_id")
		{
			mTaskId = value;
			logInfo("task id ====> %s", mTaskId.c_str());
		}
		else if (arg == "--work_type")
		{
			mWorkType = (Common::EWorkNodeType)atoi(value.c_str());
			logInfo("worktype ====> %d", mWorkType);
		}
		else if (arg == "--work_name")
		{
			mWorkName = value;
			logInfo("mWorkName ====> %s", mWorkName.c_str());
		}
		else if (arg == "--agent_id")
		{
			mAgentId = value;
		}
		else if (arg == "--public_ip")
		{
			mAgentPublicIP = value;
		}
		else if (arg == "--agent_listen_port")
		{
			mAgentListenPort = atoi(value.c_str());
			logInfo("agent_listen_port ====> %d", mAgentListenPort);
		}
		else if (arg == "--web_ip")
		{
			mWebIP = value;
			logInfo("web ip ====> %s", mWebIP.c_str());

		}
		else if (arg == "--web_port")
		{
			mWebPort = value;
			logInfo("web port ====> %s", mWebPort.c_str());
		}
		else if (arg == "--agent_connect_ip")
		{
			mAgentConnectIp = value;
			logInfo("agent connect ip ====> %s", mAgentConnectIp.c_str());
		}

		else {
			logWarning("Unknown arguments: %s:%s",flag.c_str(), value.c_str());
			//return false;
		}

	}
	return 0;
}
bool WorkApp::endTask(Common::ETaskEndReason reason) {
	Agent::StopTaskFromWorkNode endTask;
	endTask.set_taskid(mTaskId);
	endTask.set_workid(mWorkId);
	endTask.set_reason(reason);
	logInfo("endTask ===>[%s :%s]", mWorkName.c_str(),
		UtilStateHelper::getWorkNodeStateName(mWorkState).c_str());

	if (mpAgentClient != nullptr) {
		return mpAgentClient->sendMessage(Agent::EStopTaskFromWorkNode, endTask);
	}
	return true;
}
bool WorkApp::syncWorkNodeState(){
    Agent::WorkNodeStateSync mWorkNodeSync;
	mWorkNodeSync.set_taskid(mTaskId);
	mWorkNodeSync.set_workid(mWorkId);
	mWorkNodeSync.set_worktype(mWorkType);
	mWorkNodeSync.set_workstate(mWorkState);
	mWorkNodeSync.set_param("--test hehe");
	logInfo("SyncWorkNodeState ===>[%s :%s]", mWorkName.c_str(), 
		UtilStateHelper::getWorkNodeStateName(mWorkState).c_str());
    if (mpAgentClient != nullptr){
        return mpAgentClient->sendMessage(Agent::EWorkNodeStateSync, mWorkNodeSync);
    }
    return false;
}

bool WorkApp::setState(const Common::EWorkNodeState &state){
	if (mWorkState >= state)
		return false;

    mWorkState = state;
    return syncWorkNodeState();
}
bool WorkApp::onLoadConfig() {

	std::string worldconfigJson = mWorkNodeRegisterRetData.startcommand().worldconfigjson();
	std::string dirName = "configJsonFromWeb";
	bool isExist = UtilDirectory::exist(dirName);
	if (!isExist) {
		UtilDirectory::create(dirName);
	}
	string file_name = dirName + "/" +mTaskId + "_" +mWorkName +"_" +".txt";
	FILE* fp = fopen(file_name.c_str(), "w");
	fwrite(worldconfigJson.c_str(), worldconfigJson.size(), 1, fp);
	fclose(fp);

	const auto workconfiglistJson = mWorkNodeRegisterRetData.startcommand().workconfiglist();
	std::string workconfigJson;
	string workJson;
	for (int i = 0; i < workconfiglistJson.size(); i++) {
		workJson = workconfiglistJson[i].workjson();
		string workNodeId = workconfiglistJson[i].worknodeid();

		string file_name = dirName + "/" + workNodeId+ "_" + ".txt";
		FILE* fp = fopen(file_name.c_str(), "w");
		fwrite(workJson.c_str(), workJson.size(), 1, fp);
		fclose(fp);

		cybertron::json workJsonRoot;
		if (!cybertron::JsonReader::loadString(workJsonRoot, workJson))
		{
			logError("Failed to load world config json!");
			return false;
		}
		WorkNodeBaseConfig baseConfig;
		baseConfig.workType = (Common::EWorkNodeType)JsonReader::getInt(workJsonRoot, "workerType");
		baseConfig.workName = JsonReader::getString(workJsonRoot, "workName");
		baseConfig.hz = JsonReader::getInt(workJsonRoot, "hz");
		baseConfig.speed = JsonReader::getFloat(workJsonRoot, "speed");
		std::string  joinTimeSyncString  = JsonReader::getString(workJsonRoot, "joinTimeSync");
		int joinTimeSync = atoi(joinTimeSyncString.c_str());
		if (joinTimeSync > 0) {
			baseConfig.joinTimeSync = true;
		}
		else {
			baseConfig.joinTimeSync = false;
		}
		
		baseConfig.workNodeId = workNodeId;

		
		auto dependList = JsonReader::getChild(workJsonRoot, "dependHotArea");
		for (int i = 0; i < dependList.size(); ++i) {
			std::string hostVehiclesId = JsonReader::getString(dependList[i]);
			baseConfig.dependHotAreaList.push_back(hostVehiclesId);
		}
		auto taskFlagList = JsonReader::getChild(workJsonRoot, "taskFlag");
		for (int i = 0; i < taskFlagList.size(); ++i) {
			string v = taskFlagList[i];
			baseConfig.taskFlag[v] = v;
		}
		mWorkNodeBaseConfigMap[workNodeId] = baseConfig;
		if (mWorkId == workNodeId) {
			mSeflWorkNodeBaseConfig = baseConfig;
		}
	}
	cybertron::json worldJsonRoot;

	if (!cybertron::JsonReader::loadString(worldJsonRoot, worldconfigJson))
	{
		logError("Failed to load world config json!");
		return false;
	}
	mConfigSceneJsonRoot = JsonReader::getChild(worldJsonRoot, "configScene");
	auto common = JsonReader::getChild(worldJsonRoot, "common");
	mWebToken = JsonReader::getString(common, "webToken");
	//mWebHost = JsonReader::getString(common, "webUrl");
	auto hostVehicles = JsonReader::getChild(worldJsonRoot, "hostVehicles");
	for (auto it = hostVehicles.begin(); it != hostVehicles.end(); it++) {
		HostVehiclesBaseConfig baseConfig;
		string key = it.key();
		auto value = it.value();
		baseConfig.hostVehiclesId = key;
		baseConfig.workNodeId = JsonReader::getString(value, "workNodeId");
		baseConfig.hotAreaRange = JsonReader::getFloat(value, "hotAreaRange");
		baseConfig.hz = JsonReader::getInt(value, "hz");
		baseConfig.speed = JsonReader::getFloat(value, "speed");
		baseConfig.posX = JsonReader::getFloat(value, "posX");
		baseConfig.posY = JsonReader::getFloat(value, "posY");
		baseConfig.posZ = JsonReader::getFloat(value, "posZ");
		baseConfig.rotX = JsonReader::getFloat(value, "rotX");
		baseConfig.rotY = JsonReader::getFloat(value, "rotY");
		baseConfig.rotZ = JsonReader::getFloat(value, "rotZ");
		mHostVehiclesBaseConfigMap[key] = baseConfig;
	}
	return true;
}
bool WorkApp::onTaskStartBefore(){
	Master::TaskStartFromCommander* pStartConfig = mWorkNodeRegisterRetData.mutable_startcommand();
	string channelValue = mWorkNodeRegisterRetData.channelvalue();
	//if (channelValue.length() > 0) {
	//	string ownerValue = SimOneEnv::GetInstance().GetChannelValue();
	//	if (ownerValue != channelValue) {
	//		logError("channel info is wrong!!!!!!! Agent channel name %s, work channel name:%s", channelValue.c_str(), ownerValue.c_str());
	//		return false;
	//	}
	//}
	setAllWorkNodeOnTaskStart(pStartConfig);
	syncWorkDynamicConfig(mServerListenPort);
	bool b = waitForAllWorkNodeNetInfo();
	if (b) {
		logInfo("[4]:Work App Wait Dynamic Config Sucessful!");
	}
	else {
		logInfo("[4]:Work App Wait Dynamic Config Failed!");
	}
	return b;
}

bool WorkApp::onTaskStart() {
	return true;
}

bool WorkApp::onTaskStartAfter() {
	return true;
}

bool WorkApp::onTaskRunning() {
	return true;
}

bool WorkApp::onTaskStop() {
	return true;
}

std::map<std::string, WorkNodeNetInfo*>* WorkApp::getSyncWorkNodeNetInfoMap(){
	return &mSyncWorkNodeNetInfoMap;
}

WorkNodeNetInfo* WorkApp::getWorkNodeNetInfo(const std::string& workId){
	auto it = mSyncWorkNodeNetInfoMap.find(workId);
	if (it == mSyncWorkNodeNetInfoMap.end()) {
		return nullptr;
	}
	return it->second;
}

WorkNodeNetInfo* WorkApp::getWorkNodeNetInfo(const Common::EWorkNodeType& workType){
	for(auto it = mSyncWorkNodeNetInfoMap.begin(); it != mSyncWorkNodeNetInfoMap.end(); it++){
		if (it->second->workType == workType){
			return it->second; 
		}
	}
	return nullptr;
}

bool WorkApp::waitForAllWorkNodeNetInfo() {
	bool allInit = true;
	int tryCount = 0;
	while (true)
	{
		//logInfo("send EWorkNodeGetDynamicConfigFromAgent============>");
		Common::SyncWorkNodeDynamicConfig config;
		if (mWorkState != Common::EWorkNodeStateStarted) {
			logInfo("send EWorkNodeGetDynamicConfigFromAgent mWorkState != Common::EWorkNodeStateStarted============>");
			return false;
		}
		{
			allInit = true;
			for (auto it = mSyncWorkNodeNetInfoMap.begin(); it != mSyncWorkNodeNetInfoMap.end(); it++)
			{
				if (it->second->isInitNetInfo) {
					continue;
				}
				if (it->second->workType == Common::EWorkNodeType_CybertronObserver) {
					continue;
				}
				allInit = false;
				Agent::WorkNodeGetDynamicConfigFromAgent config;
				config.set_taskid(mTaskId);
				config.set_workid(it->second->workNodeId);
				config.set_worktype(it->second->workType);
				if (mpAgentClient != nullptr) {
					mpAgentClient->sendMessage(Agent::EWorkNodeGetDynamicConfigFromAgent, config);
				}
				std::this_thread::sleep_for(std::chrono::milliseconds(100));
			}
			std::this_thread::sleep_for(std::chrono::seconds(1));
			logInfo("waitForAllWorkNodeNetInfo ============>");
		}
		if (allInit) {
			return true;
		}
		tryCount += 1;
#if defined(NDEBUG)
		if (tryCount >= 180) {
			return false;
		}
#else

#endif // DEBUG

	
		
	}

	return false;

}
bool WorkApp::getWorkJsonFromWeb(cybertron::json& workRoot) {
	std::string workconfigJson;
	std::string url; 
	if (mWebPort.empty()) {
		url = "http://" + mWebIP + "/api/sessions/" + mTaskId + "/" + mWorkId;
	}
	else {
		url = "http://" + mWebIP + ":" + mWebPort + "/api/sessions/" + mTaskId + "/" + mWorkId;
	}

	std::string headervalue = "Authorization:" + mWebToken;
	std::vector<std::string>headers;
	headers.push_back(headervalue);
	int ret = UtilCurl::HttpGet(url, workconfigJson, headers);
	if (ret != 0) {
		logError("get work json failed :%s", url.c_str());
		return false;
	}
	std::string dirName = "configJsonFromWeb";
	bool isExist = UtilDirectory::exist(dirName);
	if (!isExist) {
		UtilDirectory::create(dirName);
	}
	//logInfo("getWorkJsonFromWeb %s ====>%s", url.c_str(), workconfigJson.c_str());
	string file_name = dirName + "/"+ mTaskId + "_" + mWorkName + "_WorkJsonFromWeb" + ".txt";
	FILE* fp = fopen(file_name.c_str(), "w");
	fwrite(workconfigJson.c_str(), workconfigJson.size(), 1, fp);
	fclose(fp);

	cybertron::json root;
	if (!JsonReader::loadString(root, workconfigJson))
	{
		logError("Load  json failed");
		return false;
	}
	int code = cybertron::JsonReader::getInt(root, "code");
	if (code != 0) {
		return false;
	}
	workRoot = JsonReader::getChild(root, "data");
	return true;
}
void WorkApp::syncWorkDynamicConfig(int port) {
	Common::SyncWorkNodeDynamicConfig config;
	config.set_taskid(mTaskId);
	config.set_worknodeid(mWorkId);
	config.set_worknodetype(mWorkType);
	config.set_workpublicip(mAgentPublicIP);
	config.set_workpublicport(port);
	config.set_workname(mWorkName);
	
	logInfo("[3]:Work App Sync Dynamic Config public %s, type :%s ,port: %d", mAgentPublicIP.c_str(), mWorkName.c_str(), port);
	if (mpAgentClient != nullptr) {
		mpAgentClient->sendMessage(Common::ESyncWorkNodeDynamicConfig, config);
	}
}
void WorkApp::setAllWorkNodeOnTaskStart(Master::TaskStartFromCommander* pStartConfig) {

	int req_need_node_size = pStartConfig->workconfiglist().size();
	
	std::string taskId = pStartConfig->taskid();
	std::string worldConfigJson = pStartConfig->worldconfigjson();
	
	for (int i = 0; i < req_need_node_size; i++) {
		WorkNodeNetInfo *pNodeNetInfo = new WorkNodeNetInfo();
		std::string workJson = pStartConfig->workconfiglist()[i].workjson();
		std::string workid = pStartConfig->workconfiglist()[i].worknodeid();
		Common::EWorkNodeType workType = pStartConfig->workconfiglist()[i].worktype();
		pNodeNetInfo->workNodeId = workid;
		pNodeNetInfo->workType = workType;
		pNodeNetInfo->isNeedStart = pStartConfig->workconfiglist()[i].isstart();
		
		if (pNodeNetInfo->isNeedStart) {
			mSyncWorkNodeNetInfoMap[workid] = pNodeNetInfo;
			logInfo("OnTaskStart NodeInfo ====>%s:%s ", UtilStateHelper::getWorkNodeTypeName(workType).c_str(), workid.c_str());
		}
	}
}
CybertronCoreAPI bool WorkApp::connectWorkServer(std::string workId, CybertronSyncConn& client) {
	auto it = mSyncWorkNodeNetInfoMap.find(workId);
	if (it == mSyncWorkNodeNetInfoMap.end()) {
		logError("can not find the workid :%s", workId.c_str());
		return false;
	}

	logInfo("Connect Work Server :%s:%d,[%s:%s]", it->second->publicIP.c_str(), it->second->publicPort, workId.c_str(), it->second->workName.c_str());
	return client.connect(it->second->publicIP, it->second->publicPort);
}

CybertronCoreAPI bool WorkApp::getWorkIdListByType(Common::EWorkNodeType workType, std::vector<std::string>& workIdList) {
	for (auto it = mSyncWorkNodeNetInfoMap.begin(); it != mSyncWorkNodeNetInfoMap.end(); it++) {
		if (it->second->workType == workType) {
			workIdList.push_back(it->second->workNodeId);
		}
	}
	return true;
}
CybertronCoreAPI std::string WorkApp::getHostVehicleIdByWorkId(std::string worknodeId) {
	for (auto it = mHostVehiclesBaseConfigMap.begin(); it != mHostVehiclesBaseConfigMap.end(); it++) {
		if (it->second.workNodeId == worknodeId) {
			return it->first;
		}
	}
	return "";
}
CybertronCoreAPI std::string WorkApp::getWorkIdByHostVehicleId(std::string vehicleId) {
	for (auto it = mHostVehiclesBaseConfigMap.begin(); it != mHostVehiclesBaseConfigMap.end(); it++) {
		if (it->first == vehicleId) {
			return it->second.workNodeId;
		}
	}
	return "";
}
CybertronCoreAPI bool WorkApp::isContainWorkNode(Common::EWorkNodeType workNodeType) {
	for (auto it = mWorkNodeBaseConfigMap.begin(); it != mWorkNodeBaseConfigMap.end(); it++) {
		if (it->second.workType == workNodeType) {
			return true;
		}
	}
	return false;
}
CybertronCoreAPI std::vector<std::string>* WorkApp::getWorkNodeDependHotAreaId() {
	for (auto it = mWorkNodeBaseConfigMap.begin(); it != mWorkNodeBaseConfigMap.end(); it++) {
		if (it->second.workNodeId == mWorkId) {
			return &it->second.dependHotAreaList;
		}
	}
	return nullptr;
}

bool WorkApp::setWorkNodeNetInfo(Common::SyncWorkNodeDynamicConfig* pdyConfig) {
	std::string worknodeId = pdyConfig->worknodeid();
	auto it = mSyncWorkNodeNetInfoMap.find(worknodeId);
	if (it == mSyncWorkNodeNetInfoMap.end()) {
		return false;
	}
	it->second->isInitNetInfo = true;
	it->second->publicIP = pdyConfig->workpublicip();
	it->second->publicPort = pdyConfig->workpublicport();
	it->second->agentId = pdyConfig->agentid();
	it->second->workName = pdyConfig->workname();
	logInfo("================DynamicConfig Receive PublicIP: %s", it->second->publicIP.c_str());
	logInfo("================DynamicConfig Receive PublicPort: %d", it->second->publicPort);
	logInfo("================DynamicConfig Receive Workid: %s", it->second->workNodeId.c_str());
	logInfo("================DynamicConfig Receive Worktype: %s", it->second->workName.c_str());
	return true;

}
Agent::WorkNodeRegisterRet* WorkApp::getWorkNodeRegisterRetData(){
    return &mWorkNodeRegisterRetData;
}

Common::EWorkNodeType WorkApp::getWorkNodeType(){
    return mWorkType;
}

void WorkApp::parseMessage(const Message &msg){
	std::uint16_t msgID = msg.parseMsgId();
	switch (msgID)
	{
	case Agent::ETaskBeginInitMessage:
		{
			Agent::TaskBeginInitMessage data;
			msg.toProtobuf(data);
			int length = data.argumentinfolist().size();
			for (int i = 0; i < length; i++)
			{
				string flag = data.argumentinfolist()[i].flag();
				string vallue = data.argumentinfolist()[i].value();
				parseArguments(flag, vallue);
			}
			
			Agent::WorkNodeRegister messageResponse;
			messageResponse.set_taskid(mTaskId);
			messageResponse.set_version("work-app-test0.1");
			messageResponse.set_desc("work-app-test-describe");
			messageResponse.set_param("");
			messageResponse.set_worknodeid(mWorkId);
			messageResponse.set_worktype(mWorkType);
			mpAgentClient->sendMessage(Agent::ENodeRegisterAtAgent, messageResponse);
		}
		break;
		case Agent::ENodeRegisterAtAgentRet:
		{
			logInfo("[1]:Work App Register Successful");
			msg.toProtobuf(mWorkNodeRegisterRetData);
			onLoadConfig();
            setState(Common::EWorkNodeStateStarted);
			break;
		}
		case Agent::ECommandToWorkNode:
		{
			logInfo("[FromAgent]Work App  Recv Command!");
			Agent::CommandToWorkNode data;
			msg.toProtobuf(data);
			break;
		}
		case Agent::ETaskRunningFromAgent:
		{
			logInfo("[FromAgent]Work App  Task Running!");
			if (mWorkState != Common::EWorkNodeStateInitFinish) {
				logError("it is impossible!!!!!!!!");
				return;
			} 
            setState(Common::EWorkNodeStateRunning);
			break;
		}
		case Agent::ETaskStopFromAgent:
		{
			logInfo("[FromAgent]Work App  Task Stop!");
			
			
			msg.toProtobuf(mTaskStopFromeAgent);
			
			onTaskStop();
			setState(Common::EWorkNodeStateEndingTask);

			break;
		}
		case Agent::EWorkNodeStopFromAgent:
		{
			logInfo("[FromAgent]Work App  Work Stop!");
			onWorkNodeStop();
			setState(Common::EWorkNodeStateEndingWork);
			break;
		}

		case Agent::EWorkNodeGetDynamicConfigRetFromAgent:
		{
			Common::SyncWorkNodeDynamicConfig data;
			if (!msg.toProtobuf(data))
			{
				break;
			}
			setWorkNodeNetInfo(&data);
			
			break;
		}
		default:
			break;
	}
}

bool WorkApp::isRunning(){
    return mbAgentThreadRunning;
}
void WorkApp::setServerListenPort(int listenPort) {
	mServerListenPort = listenPort;
}
void WorkApp::stopRunning(){
    mbAgentThreadRunning = false;
	mbstateCheckThreadRunning = false;
#ifdef WITH_DONGLE
	mLicense.StopDongleThread();
#endif
	onTaskStop();
}

void WorkApp::agentRunThread(){
    while(mbAgentThreadRunning){
        mpAgentClient->onTimer();
        std::this_thread::sleep_for(std::chrono::milliseconds(1));
    }
}

void WorkApp::checkLicenseThread(){
	mLicenseState = true;
	while(mLicenseState){
		std::this_thread::sleep_for(std::chrono::seconds(1));
		mLicenseState = mLicense.getDongleExist();
	}
	stopRunning();
}

bool WorkApp::isNeedCreateHotArea() {
	auto it = mHostVehiclesBaseConfigMap.begin();
	for (auto it = mHostVehiclesBaseConfigMap.begin(); it!= mHostVehiclesBaseConfigMap.end(); it++)
	{
		if (it->second.workNodeId == mWorkId) {
			return true;
		}
	}
	return false;
}
void WorkApp::stateCheckThread() {
	while (mbstateCheckThreadRunning) {

		switch (mWorkState)
		{
		case Common::EWorkNodeStateFree:
			break;
		case Common::EWorkNodeStateStarting:
			break;
		case Common::EWorkNodeStateStarted:
			{
				logInfo("[2]:Work App Task Init......");
				if (!onTaskStartBefore()) {
					logError("onTaskStartBefore return Error");
					setState(Common::EWorkNodeStateEndingWork);
					break;
				}
				if (!onTaskStart()) {
					logError("onTaskStart return Error");
					break;
				}
				if (!onTaskStartAfter()) {
					logError("onTaskStartAfter return Error");
					break;
				}
				
				setState(Common::EWorkNodeStateInitFinish);
				logInfo("[5]:Work App Task Init Finish.");
			}

			break;
		case Common::EWorkNodeStateInitFinish:
			break;
		case Common::EWorkNodeStateRunning:
			if (mbTaskHaveRun){
				break;
			}
			mbTaskHaveRun = true;
			logInfo("[6]:Work App Task Running.");
			onTaskRunning();
			break;
		case Common::EWorkNodeStateEndingWork:
			onWorkNodeStop();
			setState(Common::EWorkNodeStateWaitEnding);
			break;
		case Common::EWorkNodeStateEndingTask:

			setState(Common::EWorkNodeStateWaitEnding);
			break;
		case Common::EWorkNodeStateWaitEnding:
			break;
		case Common::EWorkNodeStateEnded:
			break;
		default:
			break;
		}
		std::this_thread::sleep_for(std::chrono::milliseconds(1));
	}
}

int WorkApp::beforeRun(){
	if (mAgentListenPort == 0) {
		mAgentListenPort = 5001;
	}
	logInfo("Connect Agent Server:%s:%d", mAgentConnectIp.c_str(), mAgentListenPort);
	mpAgentClient = std::make_shared<cybertron::AgentClient>(mAgentConnectIp.c_str(), mAgentListenPort);
    mpAgentClient->setHandlerConnected([this](){
		logInfo("[0]:Work App Connect to Agent Sucessful");
        Agent::WorkNodeRegister messageResponse;
		messageResponse.set_taskid(mTaskId);
        messageResponse.set_version("work-app-test0.1");
		messageResponse.set_desc("work-app-test-describe");
		messageResponse.set_param("");
		messageResponse.set_worknodeid(mWorkId);
		messageResponse.set_worktype(mWorkType);
		mpAgentClient->sendMessage(Agent::ENodeRegisterAtAgent, messageResponse);
	});

	mpAgentClient->setHandlerMessage([this](const Message &msg){
        parseMessage(msg);
	});
#ifdef _WIN32
	//unsigned long ret = mLicense.InitDog();
	unsigned long ret = 0;
	if (mWorkType == Common::EWorkNodeType_CybertronVehicleDynamic
	|| mWorkType == Common::EWorkNodeType_CybertronTrafficProvider) {
	//if (mWorkType == Common::EWorkNodeType_CybertronTrafficProvider) {
		ret = mLicense.InitDog();
		logInfo("InitDog   check dog. %d work type :%d", ret, mWorkType);
	}
#else
	unsigned long ret = 0;
	//if (mWorkType == Common::EWorkNodeType_CybertronVehicleDynamic
	//	|| mWorkType == Common::EWorkNodeType_CybertronTrafficProvider) {
	if (mWorkType == Common::EWorkNodeType_CybertronTrafficProvider) {
		ret = mLicense.InitDog();
		logInfo("InitDog   check dog. %d work type :%d", ret, mWorkType);
	}
#endif
	if (ret !=0){
		logError("can not init license. %d", ret);
		return 1;
	}
	mLicenseState = true;
	//std::thread thread1(&WorkApp::checkLicenseThread, this);
	//thread1.detach();

	logInfo("mLicense Init OK");

	mpAgentClient->setHandlerDisconnected([this](){
		logInfo("Work Node Disconnected!");
		//onTaskStop();
	});

	mbstateCheckThreadRunning = true;
	std::thread thread2(&WorkApp::stateCheckThread, this);
	thread2.detach();

    mbAgentThreadRunning = true;
	std::thread thread3(&WorkApp::agentRunThread, this);
	thread3.detach();
	
	return 0;
}

bool WorkApp::init(int argc, char* argv[]){
	if (!BaseApp::init(argc, argv)) {
		logError("BaseApp Init Error.");
		return false;
	}


    //if (!parseArguments(argc, argv)){
    //    logError("Work Node Can not parseArguments.");
    //    exit(1);
    //}
	string name = UtilStateHelper::getWorkNodeTypeName(mWorkType);
	if (name == "unknow") {
		name = mWorkName;
	}
	
	cybertron::setupLogFile(name);
    UtilConsole::setTitle(name);
    UtilConsole::setColor(EConsoleColor_White, EConsoleColor_Black);
	logInfo("simone version is community");
	return true;
}

CYBERTRON_END